package com.sliansoft.wechat.attendance.clientservice.impl;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.sliansoft.wechat.attendance.clientservice.ClientService;
import com.sliansoft.wechat.attendance.entity.AttendanceResult;
import com.sliansoft.wechat.attendance.entity.AttendanceRule;
import com.sliansoft.wechat.attendance.entity.CustomAttendanceResult;
import com.sliansoft.wechat.attendance.entity.CustomAttendanceRule;
import com.sliansoft.wechat.attendance.entity.ResultTrans;
import com.sliansoft.wechat.attendance.kit.BaiduMap;
import com.sliansoft.wechat.attendance.kit.ContextValue;
import com.sliansoft.wechat.attendance.mapper.AttendanceResultMapper;
import com.sliansoft.wechat.attendance.mapper.AttendanceRuleMapper;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

/**
 * <p>
 * Description:
 * </p>
 * 
 * @author zheng
 * @time 2015年12月10日 下午3:05:27
 */
@Service("clientService")
public class ClientServiceImpl implements ClientService {

	@Autowired
	private AttendanceRuleMapper attendanceRuleMapper;
	@Autowired
	private AttendanceResultMapper attendanceResultMapper;

	/**
	 * 先找出所有属于当前企业、适用于当前用户的考勤规则，然后从其中找出circule与当日匹配、不处于禁用状态、的规则，并放到集合中。
	 * 说明：排除的日期全部使用字符串表示，可以排除多个时间段，不同时间段之间用；隔开，同一时间段中，开始时间和结束时间用，隔开。
	 * 保存排除时间的时候应该采用该规则保存，注意：一个的排除时间段开始时间不能早于另一个的结束时间。
	 */
	@Override
	public JSONArray getTodayAttendance(String corpId, String userId) {
		List<CustomAttendanceRule> rules = attendanceRuleMapper.getAttendanceRuleByCorpIdAndUserId(corpId, userId);
		Iterator<CustomAttendanceRule> iterator = rules.iterator();
		JSONArray jsonRules = new JSONArray();
		DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd hh-mm");

		Date now = new Date();
		while (iterator.hasNext()) {
			AttendanceRule rule = iterator.next();

			// 处于禁用状态或不在循环周期内则从集合中删除
			if (!(rule.isRuleState()) || !isInCircule(now, rule.getCircule())) {
				continue;
			}

			if (rule.isCirculed()) { // 只有循环式的规则才有排除日期
				// 排除的日期
				String excludeStr = rule.getExclude();
				if (excludeStr != null) {
					String[] excludeDates = excludeStr.split(";");
					// 不在排除的时间段内
					if (!isExcluded(now, excludeDates)) {
						jsonRules.add(JSONObject.fromObject(rule));
					}
				}
			} else { // 对于非循环的规则，判断今天在不在签到和签退的时间之内
				try {
					Date checkInTime = formatter.parse(rule.getCheckInTime());
					Date checkOutTime = formatter.parse(rule.getCheckOutTime());
					if (checkInTime.before(now) && checkOutTime.after(now)) {
						jsonRules.add(JSONObject.fromObject(rule));
					}
				} catch (ParseException e) {
					System.out.println("获取一次性考勤，日期转换时出错");
					e.printStackTrace();
				}
			}
		}
		return jsonRules;
	}

	/**
	 * 根据企业corpId得到access_token
	 * 
	 * @param corpId
	 * @return
	 */
	@Override
	public String getAccessTokenByCorpId(String corpId) {
		String access_tokens = null;
		if (corpId != null)
			access_tokens = attendanceRuleMapper.getAccessTokenByCorpId(corpId);

		return access_tokens;
	}

	/**
	 * 
	 */
	@Override
	public JSONObject getRuleDetail(String ruleId) {
		// String serviceRuleId = ruleId;
		System.out.println("service" + ruleId);
		AttendanceRule ruleDetail = attendanceRuleMapper.getAttendanceRuleByRuleId(ruleId);
		JSONObject jsonRuleDetail = JSONObject.fromObject(ruleDetail);
		return jsonRuleDetail;
	}

	/**
	 * 判断今天在不在循环周期中
	 * 
	 * @param now
	 * @param circule
	 * @return
	 */
	private static boolean isInCircule(Date now, String circule) {
		SimpleDateFormat format = new SimpleDateFormat("EEEE");
		String today = format.format(now);// 今天星期几
		String[] weekDays = circule.split("、");
		for (String weekDay : weekDays) {
			if (weekDay.equals(today))
				return true;
		}
		return false;
	}

	/**
	 * 判断在不在排除的时间段内，在排除的时间段内返回true，否则返回false
	 * 
	 * @param now
	 * @param excludeDates
	 * @return
	 */
	private static boolean isExcluded(Date now, String[] excludeDates) {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		for (String str : excludeDates) {
			String dateStr[] = str.split(",");
			Date startDate = null, endDate = null;
			try {
				startDate = format.parse(dateStr[0]);
				endDate = format.parse(dateStr[1]);
			} catch (ParseException e) {
				System.out.println("日期转换的时候出错");
				e.printStackTrace();
			}
			// 在排除时间段内
			if (now.compareTo(startDate) > 0 && now.compareTo(endDate) < 0) {
				return true;
			} else {
				continue;
			}
		}
		return false;
	}

	/**
	 * 处理签到业务逻辑，签到和签退的业务逻辑是分开的， 需要注意的是返回给用户看到的结果和保存在数据库中的结果是不一样的，
	 * 用户看到的结果只是用户本次操作的结果：成功或者失败，存在数据库中的结果是，
	 * 用户本次操作所携带的数据经过逻辑判断之后得出的结果，迟到、早退、未签到、位置偏。
	 * 
	 * @param trans
	 *            其中包含了ruleId、currentDay、userId
	 */
	@Override
	public String checkIn(ResultTrans trans) {
		String returnStr = null;
		SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd");
		// 传递过来的日期格式：时间戳
		String now = formater.format(new Date(Long.valueOf(trans.getCurrentTime())));

		// 根据userId、ruleId、currentDay查询考勤结果
		AttendanceResult attendanceResult = attendanceRuleMapper.getAttendanceResultInfo(trans.getRuleId(),
				trans.getUserId(), now);
		String resultStr = judgeCheckIn(trans);

		// 查询结果为空，表明该用户是在当天第一次点击该规则，则插入新纪录
		if (attendanceResult == null) {
			String resultId = UUID.randomUUID().toString().trim().replaceAll("-", "");
			trans.setResultId(resultId);
			attendanceRuleMapper.insertCheckInResult(trans);// 更新结果表
			attendanceRuleMapper.insertUserRuleResult(resultId, trans.getRuleId(), trans.getUserId(), now);// 更新关联表
			returnStr = "check in success";
		} else if (attendanceResult.getCheckInTime() == null) {//先签到后签退
			returnStr = "can't checkIn after checkOut";
		} else {
			returnStr = "you have checked in";
		}
		trans.setResultStr(resultStr);
		return returnStr;
	}

	/**
	 * 根据用户考勤的数据判断本次考勤的结果，该结果是要向数据库中插入的
	 * 
	 * @param trans
	 *            其中包含了用户的考勤数据和考勤规则中定义的数据
	 * @return 根据考勤数据计算出来的结果
	 * @throws ParseException
	 */
	private String judgeCheckIn(ResultTrans trans) {
		SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm");
		StringBuilder checkInResult = new StringBuilder();
		// 规则规定的考勤时间：2016-01-09 08:00
		String checkInTime = trans.getCheckTime();
		// 允许推迟的时间：整数表示的分钟数
		int delayTime = Integer.valueOf(trans.getMarginTime());
		// 签到的时间，时间戳
		String currentTime = trans.getCurrentTime();

		String centerStr = trans.getCenterStr();
		String latitude = trans.getLatitude();
		String longitude = trans.getLongitude();
		int radius = Integer.valueOf(trans.getRadius());

		long checkInTimeStamp = 0;
		try {
			checkInTimeStamp = (formater.parse(checkInTime).getTime()) / 60000;
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Long currentTimeStamp = Long.valueOf(currentTime) / 60000;

		if (currentTimeStamp - checkInTimeStamp > delayTime) {
			checkInResult.append("迟到");
		} else {
			checkInResult.append("签到正常");
		}
		// 得到两点之间的距离，单位为m
		int distance = BaiduMap.getDistance(centerStr, latitude, longitude);
		if (distance > radius) {
			checkInResult.append("位置偏移");
		} else {
			checkInResult.append("位置正常");
		}
		// 将签到时间戳改成时间格式然后保存
		trans.setCurrentTime(formater.format(new Date(Long.valueOf(currentTime))));
		return checkInResult.toString();
	}

	@Override
	public String checkOut(ResultTrans trans) {
		String returnStr = null;
		SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd");
		String now = formater.format(new Date(Long.valueOf(trans.getCurrentTime())));

		System.out.println("测试：ruleId = " + trans.getRuleId() + ", userId = " + trans.getUserId() + ", now = " + now);

		// 根据userId、ruleId、currentDay查询考勤结果
		AttendanceResult attendanceResult = attendanceRuleMapper.getAttendanceResultInfo(trans.getRuleId(),
				trans.getUserId(), now);
		String resultStr = judgeCheckOut(trans);

		// 如果为空，表明没有签到
		if (attendanceResult == null) {
			String resultId = UUID.randomUUID().toString().trim().replaceAll("-", "");
			trans.setResultId(resultId);
			attendanceRuleMapper.insertCheckOutResult(trans);// 更新结果表
			attendanceRuleMapper.insertUserRuleResult(resultId, trans.getRuleId(), trans.getUserId(), now);// 更新关联表
			returnStr = "check out success";
		} else if (attendanceResult.getCheckOutTime() == null) { // 签到了，但没有签退，则更新结果记录
			trans.setResultStr(ContextValue.RESULT_STR[2]);
			trans.setResultId(attendanceResult.getResultId());
			attendanceRuleMapper.updateCheckOutResult(trans);
			returnStr = "check out success";
		} else {
			returnStr = "you have check out";
		}
		trans.setResultStr(resultStr);
		return returnStr;
	}

	private String judgeCheckOut(ResultTrans trans) {
		SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm");
		StringBuilder checkOutResult = new StringBuilder();
		// 规则规定的考勤时间：2016-01-09 08:00
		String checkOutTime = trans.getCheckTime();
		// 允许提前的时间：整数表示的分钟数
		int leadTime = Integer.valueOf(trans.getMarginTime());
		// 签退的时间，时间戳
		String currentTime = trans.getCurrentTime();

		String centerStr = trans.getCenterStr();
		String latitude = trans.getLatitude();
		String longitude = trans.getLongitude();
		int radius = Integer.valueOf(trans.getRadius());

		long checkOutTimeStamp = 0;
		try {
			checkOutTimeStamp = (formater.parse(checkOutTime).getTime()) / 60000;
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Long currentTimeStamp = Long.valueOf(currentTime) / 60000;

		if (checkOutTimeStamp - currentTimeStamp > leadTime) {
			checkOutResult.append("早退");
		} else {
			checkOutResult.append("签退正常");
		}
		// 得到两点之间的距离，单位为m
		int distance = BaiduMap.getDistance(centerStr, latitude, longitude);
		if (distance > radius) {
			checkOutResult.append("位置偏移");
		} else {
			checkOutResult.append("位置正常");
		}
		// 将签退时间戳改成时间格式然后保存
		trans.setCurrentTime(formater.format(new Date(Long.valueOf(currentTime))));
		return checkOutResult.toString();
	}

	/**
	 * 查出当前用户的所有考勤记录，这里需要注意的是：为了前端方便显示，这里需要将考勤结果封装成两层的json数组形式
	 * CustomAttendanceResult在AttendanceResult的基础上多了ruleName和creator属性
	 * 员工没有进行考勤的记录什么时候插进去？
	 */
	@Override
	public JSONArray getAttendanceResult(String userId) {
		List<CustomAttendanceResult> results = attendanceResultMapper.getAttendanceResult(userId);
		Iterator<CustomAttendanceResult> iterator = results.iterator();
		JSONArray jsonResults = new JSONArray();
		Map<String, Map<String, CustomAttendanceResult>> resultMap = new HashMap<String, Map<String, CustomAttendanceResult>>();
		String resultDate = null;

		while (iterator.hasNext()) {
			CustomAttendanceResult result = iterator.next();

			// 签到时间优先决定结果所属类别，2015-12-01 08:02:32:126
			String resultTime = result.getCheckInTime();
			if (resultTime == null)
				resultTime = result.getCheckOutTime();
			resultDate = resultTime.substring(0, 10);

			if (resultMap.containsKey(resultDate)) {
				resultMap.get(resultDate).put(result.getResultId(), result);
			} else {
				Map<String, CustomAttendanceResult> subResult = new HashMap<String, CustomAttendanceResult>();
				subResult.put(result.getResultId(), result);
				resultMap.put(resultDate, subResult);
			}
		}

		if (resultMap.isEmpty())
			return null;

		jsonResults.element(resultMap);
		return jsonResults;
	}
}
